#include "clientsocket.h"
#include <QThread>
#include <QFile>
#include <QFileInfo>
#include <QApplication>

ClientSocket::ClientSocket(QObject *parent)
    : QTcpSocket{parent}
{
    connect(this,&ClientSocket::connected,this,[=](){
        is_connected = true;
    });
    connect(this,&ClientSocket::disconnected,this,[=](){
        is_connected = false;
    });
    connect(this,&ClientSocket::readyRead,this,&ClientSocket::recv);
}

ClientSocket *ClientSocket::glob()
{
    static ClientSocket client;
    if(client.isConnected()){
        return &client;
    }
    if(!client.readConfFile(QApplication::applicationDirPath()+"/client.conf")){
        return nullptr;
    }
    client.connectToServer();
    return &client;
}

void ClientSocket::login(const QString &user_name, const QString &user_password){
    QJsonDocument doc;
    QJsonObject obj;
    obj["status"] = "login";
    obj["user_name"] = user_name;
    obj["user_password"] = user_password;
    doc.setObject(obj);
    write(doc.toJson());
}

void ClientSocket::signup(const QString &user_name, const QString &user_password)
{
    QJsonDocument doc;
    QJsonObject obj;
    obj["status"] = "signup";
    obj["user_name"] = user_name;
    obj["user_password"] = user_password;
    doc.setObject(obj);
    write(doc.toJson());
}

void ClientSocket::secretChat(const QString &user_name, const QString &msg)
{
    QJsonDocument doc;
    QJsonObject obj;
    obj["status"] = "secret_chat";
    obj["send_user"] = user_name;
    obj["send_message"] = msg;
    doc.setObject(obj);
    write(doc.toJson());
}

void ClientSocket::friendListQuery()
{
    QJsonDocument doc;
    QJsonObject obj;
    obj["status"] = "friend_list_query";
    doc.setObject(obj);
    write(doc.toJson());
}

void ClientSocket::friendApplyListQuery()
{
    QJsonDocument doc;
    QJsonObject obj;
    obj["status"] = "friend_apply_list_query";
    doc.setObject(obj);
    write(doc.toJson());
}

void ClientSocket::sendFile(const QString &send_user,QFile &file)
{
    QFileInfo info(file);
    QJsonObject obj;
    QJsonDocument doc;
    if(info.size() <= 1024){
        obj["send_user"] = send_user;
        obj["status"] = "upload";
        obj["file_name"] = info.fileName();
        obj["total_size"] = info.size();
        obj["index"] = 0;
        obj["data"] = QString(file.readAll().toBase64());
        doc.setObject(obj);
        write(doc.toJson());
    }else{
        qint64 total_size = info.size();
        int index = 0;
        while(true){
            obj["send_user"] = send_user;
            obj["status"] = "upload";
            obj["file_name"] = info.fileName();
            obj["total_size"] = total_size;
            obj["index"] = index;
            QByteArray data = file.read(512);
            obj["data"] = QString(data.toBase64());
            doc.setObject(obj);
            write(doc.toJson());
            flush();
            QThread::usleep(100000);
            index++;
            if(data.size() < 512){
                break;
            }
        }
    }
}

bool ClientSocket::readConfFile(const QString &path)
{
    QFile file(path);
    if(!file.open(QIODevice::ReadOnly)){
        return false;
    }
    QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
    QJsonObject obj = doc.object();
    server_ip = obj["server_ip"].toString();
    server_port = obj["server_port"].toInt();
    return true;
}

void ClientSocket::connectToServer()
{
    connectToHost(server_ip,server_port);
}

void ClientSocket::recv()
{
    QJsonDocument doc = QJsonDocument::fromJson(readAll());
    QJsonObject reply_obj = doc.object();
    QString status = reply_obj.value("status").toString();
    if(status == "login_ok" || status == "login_fail"){
        emit loginReply(reply_obj);
    }
    else if(status == "signup_ok" || status == "signup_fail"){
        emit signupReply(reply_obj);
    }
    else if(status == "friend_list"){
        emit friendListReply(reply_obj);
    }
    else if(status == "secret_chat"){
        emit recvSecretChat(reply_obj);
    }
    else if(status == "download"){
        emit fileRead(reply_obj);
    }
    else if(status == "friend_apply_list"){
        emit friendApplyList(reply_obj);
    }
}
